; void blit(Uint8 *imagen, Uint32 ancho_imagen, Uint32 alto_imagen, Uint32 x, Uint32 y, Color rgb);

extern screen_pixeles

; constantes globales

	%include "constantes.mac"

; constantes locales

	%define mascara_4to_byte				0xff000000
	%define pila_local						8
	%define bytes_en_128_bits				16
	%define pixeles_completos_en_128_bits	5
	%define bytes_en_5_pixeles				15

; parametros

	%define imagen							[ebp + 08]
	%define ancho_imagen					[ebp + 12]
	%define alto_imagen						[ebp + 16]
	%define coord_x							[ebp + 20]
	%define coord_y							[ebp + 24]
	%define rgb								[ebp + 28]

; variables

	%define fila							[ebp - 4]
	%define partes							[ebp - 8]

global blit

section .text

blit:

	push ebp								; creo el marco de la pila
	mov ebp, esp							; creo el marco de la pila
	sub esp, pila_local						; pido memoria en la pila
	push ebx								; salvo registros convencion C
	push edi								; salvo registros convencion C
	push esi								; salvo registros convencion C
	
inicializo_variables:

	mov edi, dword [screen_pixeles]			; edi = puntero a al destino (pantalla)
	
	mov eax, ancho_pantalla_bytes
	mov ebx, coord_y
	mul ebx
	add edi, eax							; edi en la fila adecuada
	
	mov eax, coord_x
	mov ebx, bytes_por_pixel
	mul ebx
	add edi, eax							; edi en el punto adecuado

	mov esi, imagen							; esi = puntero a la fuente (imagen)

	mov ecx, alto_imagen					; ecx = contador de filas
	
calcular_partes:

	mov eax, ancho_imagen
	mov ebx, bytes_por_pixel
	mul ebx
	mov ebx, bytes_en_128_bits
	div ebx
	mov partes, eax

ciclo_filas:

	mov edx, ancho_imagen					; edx = contador de columnas
	
optimizacion:

	mov fila, ecx
	mov ecx, partes							; ecx = veces que se puede partir una fila en 5 pixeles
	
ciclo_optimizacion:

	mov ebx, rgb							; ebx = pixel off y un byte basura
	and ebx, mascara_pixel					; ebx = pixel off y un byte en 0
	movdqu xmm7, [esi]						; xmm7 = 128 bits de la imagen
	movdqu xmm6, [edi]						; xmm6 = 128 bits del fondo
	
primer_pixel:

	movd eax, xmm7							; eax = un pixel de la imagen y byte de basura
	and eax, mascara_pixel					; eax = un pixel de la imagen y un byte en 0
	cmp eax, ebx							; comparo el pixel con el color off
	je primer_pixel_es_color_off
	movd xmm5, eax
	jmp segundo_pixel
	
primer_pixel_es_color_off:

	movd eax, xmm6							; eax = un pixel del fondo y byte de basura
	and eax, mascara_pixel
	movd xmm5, eax

segundo_pixel:

	psrldq xmm7, bytes_por_pixel
	psrldq xmm6, bytes_por_pixel
	movd eax, xmm7							; eax = un pixel de la imagen y byte de basura
	and eax, mascara_pixel					; eax = un pixel de la imagen y un byte en 0
	cmp eax, ebx							; comparo el pixel con el color off
	je segundo_pixel_es_color_off
	movd xmm4, eax
	pslldq xmm4, bytes_por_pixel
	por xmm5, xmm4
	jmp tercer_pixel
	
segundo_pixel_es_color_off:

	movd eax, xmm6							; eax = un pixel del fondo y byte de basura
	and eax, mascara_pixel
	movd xmm4, eax
	pslldq xmm4, bytes_por_pixel
	por xmm5, xmm4
	
tercer_pixel:

	psrldq xmm7, bytes_por_pixel
	psrldq xmm6, bytes_por_pixel
	movd eax, xmm7							; eax = un pixel de la imagen y byte de basura
	and eax, mascara_pixel					; eax = un pixel de la imagen y un byte en 0
	cmp eax, ebx							; comparo el pixel con el color off
	je tercer_pixel_es_color_off
	movd xmm4, eax
	pslldq xmm4, bytes_por_pixel*2
	por xmm5, xmm4
	jmp cuarto_pixel
	
tercer_pixel_es_color_off:

	movd eax, xmm6							; eax = un pixel del fondo y byte de basura
	and eax, mascara_pixel
	movd xmm4, eax
	pslldq xmm4, bytes_por_pixel*2
	por xmm5, xmm4
	
cuarto_pixel:

	psrldq xmm7, bytes_por_pixel
	psrldq xmm6, bytes_por_pixel
	movd eax, xmm7							; eax = un pixel de la imagen y byte de basura
	and eax, mascara_pixel					; eax = un pixel de la imagen y un byte en 0
	cmp eax, ebx							; comparo el pixel con el color off
	je cuarto_pixel_es_color_off
	movd xmm4, eax
	pslldq xmm4, bytes_por_pixel*3
	por xmm5, xmm4
	jmp quinto_pixel
	
cuarto_pixel_es_color_off:

	movd eax, xmm6							; eax = un pixel del fondo y byte de basura
	and eax, mascara_pixel
	movd xmm4, eax
	pslldq xmm4, bytes_por_pixel*3
	por xmm5, xmm4
	
quinto_pixel:

	psrldq xmm7, bytes_por_pixel
	psrldq xmm6, bytes_por_pixel
	movd eax, xmm7							; eax = un pixel de la imagen y byte de basura
	and eax, mascara_pixel					; eax = un pixel de la imagen y un byte en 0
	cmp eax, ebx							; comparo el pixel con el color off
	je quinto_pixel_es_color_off
	movd eax, xmm7
	movd xmm4, eax
	pslldq xmm4, bytes_por_pixel*4
	por xmm5, xmm4
	jmp guardar_pixeles
	
quinto_pixel_es_color_off:

	movd eax, xmm6							; eax = un pixel del fondo y byte de basura
	and eax, mascara_pixel					; eax = un pixel del fondo con un byte en 0
	movd ebx, xmm7							; ebx = un pixel de la imagen y byte de basura
	and ebx, mascara_4to_byte				; ebx = ceros y un byte de basura de la imagen
	or eax, ebx
	movd xmm4, eax
	pslldq xmm4, bytes_por_pixel*4
	por xmm5, xmm4
	
guardar_pixeles:

	movdqu [esi], xmm5

	sub edx, pixeles_completos_en_128_bits
	
	add esi, bytes_en_5_pixeles
	add edi, bytes_en_5_pixeles

	dec ecx
	cmp ecx, 0
	je fin_optimizacion
	jmp ciclo_optimizacion
	
fin_optimizacion:

	mov ecx, fila

ciclo_columnas:

	mov eax, [esi]							; eax = pixel de la imagen con un byte de basura
	and eax, mascara_pixel					; eax = pixel de la imagen con un byte en 0

	mov ebx, rgb							; ebx = pixel off con byte de basura
	and ebx, mascara_pixel					; ebx = pixel off con byte en 0

	cmp eax, ebx							; comparo buffer contra color off
	je copiar_pixel_del_fondo				; si son iguales entonces ES color off

	jmp siguiente_columna

copiar_pixel_del_fondo:

	mov ebx, [edi]							; ebx = pixel del fondo con un byte de basura
	and ebx, mascara_pixel					; ebx = pixel del fondo con un byte en 0

	mov eax, [esi]							; eax = pixel de la imagen con un byte de basura
	and eax, mascara_4to_byte				; eax = ceros con un byte de basura de la imagen
	or ebx, eax								; ebx = pixel del fondo con un byte de basura de la imagen

	mov [esi], ebx							; piso la imagen

siguiente_columna:

	add esi, bytes_por_pixel				; avanzo puntero fuente
	add edi, bytes_por_pixel				; avanzo puntero destino

	dec edx
	cmp edx, 0
	je siguiente_fila
	jmp ciclo_columnas
	
siguiente_fila:

	mov eax, ancho_imagen
	shr eax, 2
	shl eax, 2
	mov ebx, ancho_imagen
	sub ebx, eax

	add esi, ebx
	add edi, ancho_pantalla_bytes

	mov eax, ancho_imagen
	add eax, ancho_imagen
	add eax, ancho_imagen

	sub edi, eax

	dec ecx
	cmp ecx, 0
	je fin
	jmp ciclo_filas

fin:

	pop esi									; desarmo el stack frame
	pop edi									; desarmo el stack frame
	pop ebx									; desarmo el stack frame
	add esp, pila_local						; pido memoria en la pila
	pop ebp									; desarmo el stack frame

	ret
